package com.goldmantis.alitrip.controller.authentication;

import com.alibaba.fastjson.JSON;
import com.goldmantis.alitrip.common.*;
import com.goldmantis.alitrip.common.annotation.Log;
import com.goldmantis.alitrip.common.redis.RedisService;
import com.goldmantis.alitrip.common.shiro.JWTFilter;
import com.goldmantis.alitrip.common.shiro.JWTToken;
import com.goldmantis.alitrip.common.shiro.JWTUtil;
import com.goldmantis.alitrip.common.sysenum.EnumLogCatagory;
import com.goldmantis.alitrip.common.sysenum.EnumOperationType;
import com.goldmantis.alitrip.common.utils.ToolUtil;
import com.goldmantis.alitrip.pojo.SysLog;
import com.goldmantis.alitrip.pojo.UvSysUser;
import com.goldmantis.alitrip.service.SysLogService;
import com.goldmantis.alitrip.service.UvSysUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author:Shmily
 * @Description:
 * @Date:Create in 11:05 2018/2/6
 */
@Controller
@Api(description = "系统登陆登出")
public class LoginController {

    @Autowired
    private UvSysUserService uvSysUserService;

    @Autowired
    private RedisService redisService;

    @Autowired
    private SysLogService sysLogService;


    @PostMapping(value = "/login")
    @ApiOperation(value = "登陆系统", httpMethod = "POST")
    public ResponseEntity<ReturnMessage> login(@Valid @RequestBody LoginModel loginModel) throws Exception {
        Subject subject = SecurityUtils.getSubject();
        try {
            List<UvSysUser> sysUserList = uvSysUserService.getUvSysUserList(loginModel.getUserName().trim());
            UvSysUser user;
            if (sysUserList != null && !sysUserList.isEmpty()) {
                user = sysUserList.get(0);
            } else {
                throw new UnknownAccountException();
            }
            JWTToken jwtToken = new JWTToken(loginModel.getUserName().trim(), loginModel.getPassword().trim(), user);
            subject.login(jwtToken);

            //记录原始密码，但不存数据库
            user.setOriginalPassword(loginModel.getPassword());

            String jwt = JWTUtil.sign(user.getUserId());
            redisService.set(jwt, JSON.toJSONString(user), ToolUtil.REDIS_TOKEN_EXPIRE);

            //记录登陆日志
            SysLog sysLog = getBaseSysLog();
            sysLog.setOperateUserId(user.getUserId());
            sysLog.setOperateAccount(user.getAccount().concat("(").concat(user.fullName).concat(")"));
            sysLog.setCategoryId(EnumLogCatagory.login.getValue());
            sysLog.setDescription("用户登陆");
            sysLog.setOperateTypeId(String.valueOf(EnumOperationType.login.getValue()));
            sysLog.setOperateType(EnumOperationType.login.getText());


            this.sysLogService.insert(sysLog);

            Map<String, Object> map = new HashMap<>();
            //给前端用户信息时，不给原始密码
            user.setOriginalPassword(null);
            map.put("accessToken", jwt);
            map.put("userInfo", user);

            return ResponseEntity.ok(ReturnMessage.success(map));
        } catch (UnknownAccountException exception) {
            throw new UnknownAccountException("账号不存在!");
        } catch (IncorrectCredentialsException exception) {
            throw new IncorrectCredentialsException("错误的凭证，用户名或密码不正确!");
        } catch (LockedAccountException exception) {
            throw new LockedAccountException("账户已锁定!");
        } catch (ExcessiveAttemptsException exception) {
            throw new ExcessiveAttemptsException("错误次数过多!");
        } catch (AuthenticationException exception) {
            throw new AuthenticationException("认证失败!");
        } catch (Exception exception) {
            exception.printStackTrace();
            throw exception;
        }
    }

    @PostMapping(value = "/logout")
    @ApiOperation(value = "注销", httpMethod = "POST", notes = "header里需要有Authorization参数")
    @Log(operationName = "用户登出", logCatagory = EnumLogCatagory.login, operationType = EnumOperationType.logout)
    public ResponseEntity<ReturnMessage> logout(HttpServletRequest request) {
        try {
            String accessToken = JWTFilter.getAccessToken(request);
            if (StringUtils.isNotEmpty(accessToken)) {
                redisService.del(accessToken);
            }
            Subject subject = SecurityUtils.getSubject();
            subject.logout();
            return ResponseEntity.ok(ReturnMessage.success("注销成功！"));
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ReturnMessage.failure(e));
        }
    }

    private SysLog getBaseSysLog() {
        //获取httpRequestServlet
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();

        SysLog sysLog = new SysLog();
        sysLog.setOperateTime(new Date());
        sysLog.setIpAddress(request.getRemoteAddr());
        sysLog.setHost(request.getRemoteHost());
        sysLog.setBrowser(request.getHeader("user-agent"));
        sysLog.setxRealIp(request.getHeader("x-forwarded-for"));
        sysLog.setExecuteResult(1);
        sysLog.setExecuteResultJson(request.getRequestURL().toString());

        UvSysUser user = UserThreadLocal.get();

        return sysLog;
    }


}
